#include "engine.h"
#include <string>
#include <list>
#include <set>
#include <map>
#include <assert.h>
#include <sys\types.h>
#include <sys\stat.h>
using namespace std;

namespace HW
{

struct FileProperty
{
	//wstring u_name;
	string name;
	string extension;
	string path;

	double size;

	bool readOnly;

	SYSTEMTIME creationTime;
	SYSTEMTIME lastAccessTime;
	SYSTEMTIME lastWriteTime;
};

struct DirProperty
{
	string path;
	set<string> file;

	DirProperty* parentDir;
	list<DirProperty*> childDir;
};

DirProperty lDirTree;
map<string,FileProperty> lFileMap;
static string lReturnPath;

wchar_t* char2wchar ( string ansistr )
{
	int a = ansistr.size();
	wchar_t* unicodestr = SysAllocStringLen(NULL, a);
	::MultiByteToWideChar(CP_ACP, 0, ansistr.c_str(), a, unicodestr, a);
	return unicodestr;
}

LPCSTR wchar2char ( wstring unicodestr )
{
	int a = unicodestr.size()+1;
	char *ansistr = new char[a];
	::WideCharToMultiByte(CP_ACP, 
							0, 
							unicodestr.c_str(), 
							-1, 
							ansistr, 
							a, 
							NULL, 
							NULL);
	return ansistr;
}
void _i_TransverseDirectory(string _path,DirProperty* dirTree,map<string,FileProperty>& file)
{
	wstring path = char2wchar ( _path );
    WIN32_FIND_DATA data;
    wstring fname = path + L"\\*.*";
    HANDLE h = FindFirstFile((fname.c_str()),&data);
    if(h != INVALID_HANDLE_VALUE)
    {
		#if _DEBUG
		AppLog ( wchar2char(path) );
		#endif

        do {
            if( (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
            {
                if( !(data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) 
                    && !(data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
                {
                    // make sure we skip "." and "..".  Have to use strcmp here because
                    // some file names can start with a dot, so just testing for the 
                    // first dot is not suffient.
					if( wstring(data.cFileName).compare(L".") != 0 &&wstring(data.cFileName).compare(L"..") != 0)
                    {
						DirProperty* newDir = new DirProperty;
						newDir->path = wchar2char(data.cFileName);
						newDir->parentDir = dirTree;

						dirTree->childDir.push_back ( newDir );

                        // We found a sub-directory, so get the files in it too
                        fname = path + L"\\" + data.cFileName;
                        // recurrsion here!
						_i_TransverseDirectory(wchar2char(fname),newDir,file);
                    }
                }
 
            }
            else
            {
                LARGE_INTEGER sz;
                // All we want here is the file size.  Since file sizes can be larger
                // than 2 gig, the size is reported as two DWORD objects.  Below we
                // combine them to make one 64-bit integer.
                sz.LowPart = data.nFileSizeLow;
                sz.HighPart = data.nFileSizeHigh;

				FileProperty newFile;

				//TODO: file name
				string newName = wchar2char( data.cFileName );

				string::size_type idx = newName.rfind('.');

				if(idx != string::npos)
					newFile.extension = newName.substr(idx+1);
				else
					newFile.extension = "";

				newFile.name = _path + "\\" + newName;
				//newFile.u_name = data.cFileName;
				newFile.path = _path;
				newFile.size = sz.QuadPart / 1000000.0;
				newFile.readOnly = data.dwFileAttributes & FILE_ATTRIBUTE_READONLY;
				
				//TODO: time!
				SYSTEMTIME univTime;
				FileTimeToSystemTime ( &data.ftLastAccessTime , &univTime );
				SystemTimeToTzSpecificLocalTime ( NULL , &univTime , &newFile.lastAccessTime );
				FileTimeToSystemTime ( &data.ftCreationTime , &univTime );
				SystemTimeToTzSpecificLocalTime ( NULL , &univTime , &newFile.creationTime );
				FileTimeToSystemTime ( &data.ftLastWriteTime , &univTime );
				SystemTimeToTzSpecificLocalTime ( NULL , &univTime , &newFile.lastWriteTime );

				file[newName] = newFile;

				dirTree->file.insert ( newName );

				#ifdef _DEBUG
				AppLog ( newName.c_str() );
				#endif
 
            }
        }while( FindNextFile(h,&data) != 0);
        FindClose(h);
 
    }
}

void _i_InitFileSystem ( void )
{
	int lReqBuffSize = GetCurrentDirectoryA ( 0 , NULL );
	char* lPath = new char[lReqBuffSize];
	GetCurrentDirectoryA ( lReqBuffSize , lPath );
	lDirTree.parentDir = NULL;
	lDirTree.path = lPath;
	_i_TransverseDirectory ( lPath , &lDirTree , lFileMap );
	delete lPath;
}

void RegisterAbstractPath(const_str path)
{
	lDirTree.parentDir = NULL;
	lDirTree.path = path;
	_i_TransverseDirectory ( path , &lDirTree , lFileMap );
}

const_str AbstractPath(const_str path)
{
	lReturnPath = path;
	if ( lReturnPath.find ( "abstract::" ) == 0 )
	{
		lReturnPath = path + 10;
		if ( lFileMap.find ( lReturnPath ) == lFileMap.end() )
			lReturnPath = "";
		else
			lReturnPath = lFileMap[lReturnPath].name;
	}
	return lReturnPath.c_str();
}

void SetZipStreamPassword(const_str url, const_str password)
{
}

bool _i_FileExist ( const_str path )
{
	struct stat newStat;
	return (stat(path, &newStat) != -1);
}

}